package main

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/kotocean/cricket/auth/cache"
	"github.com/kotocean/cricket/auth/db"
	"github.com/kotocean/cricket/auth/db/models"
	"github.com/kotocean/cricket/auth/token"
)

func main() {
	router := gin.Default()

	router.POST("/active", activeHandler)
	router.POST("/login", loginHandler)
	router.GET("/check", checkHandler)
	router.POST("/logout", logoutHandler)

	router.Run(":8080")
}

func activeHandler(c *gin.Context) {
	var json models.Client
	if err := c.ShouldBindJSON(&json); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"status": err.Error()})
		return
	}

	client, err := db.GetClientInfo(json.ClientId)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"status": "Client未注册"})
		return
	}

	if json.Secret != client.Secret {
		c.JSON(http.StatusUnauthorized, gin.H{"status": "密码错误"})
		return
	}

	clientMark := GenerateClientMark(client.Id, client.ClientId)
	c.Header("Authorization", "Bearer "+clientMark)
	c.JSON(http.StatusOK, gin.H{"status": "Client已激活"})
}

func logoutHandler(c *gin.Context) {
	//获取客户端指纹
	clientMark := strings.Replace(c.GetHeader("Authorization"), "Bearer ", "", 1)
	if clientMark == "" {
		c.JSON(http.StatusForbidden, gin.H{"status": "Client未激活"})
		return
	}
	httpStatus, _, _ := check(clientMark)

	if httpStatus == http.StatusOK {
		//无效化cache
		cacheErr := cache.InvalidateToken(clientMark)
		if cacheErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": "token从cache无效化失败"})
			return
		}
		//无效化数据库
		_, dbErr := db.InvalidateToken(clientMark)
		if dbErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": "token从数据库无效化失败"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": "已退出登录"})
	} else {
		c.JSON(http.StatusForbidden, gin.H{"status": "当前已处于登出状态"})
	}
}

func checkHandler(c *gin.Context) {
	//获取客户端指纹
	clientMark := strings.Replace(c.GetHeader("Authorization"), "Bearer ", "", 1)
	if clientMark == "" {
		c.JSON(http.StatusForbidden, gin.H{"status": "Client未激活"})
		return
	}
	httpStatus, status, token := check(clientMark)

	switch httpStatus {
	case http.StatusFound:
		c.JSON(http.StatusFound, gin.H{"status": status, "path": "/login"})
		break
	case http.StatusOK:
		c.JSON(http.StatusOK, gin.H{"status": status, "token": token})
		break
	case http.StatusInternalServerError:
		c.JSON(http.StatusInternalServerError, gin.H{"status": status})
		break
	}
}

func check(clientMark string) (int, string, string) {

	result, err := cache.GetToken(clientMark)
	if err != nil {
		//cache中不存在client对应的token
		record, dbErr := db.GetRecord(clientMark)
		if dbErr != nil {
			// token在数据库中不存在
			return http.StatusFound, "用户未登录", ""
		}
		pass, _ := ValidateToken(record.ExpiresAt, record.Valid)
		if pass {
			cacheErr := cache.SaveToken(clientMark, record.Token, record.ExpiresAt)
			if cacheErr != nil {
				return http.StatusInternalServerError, "token保存到cache失败", ""
			}
			return http.StatusOK, "用户已登录", record.Token
		} else {
			return http.StatusFound, "token不可用或已过期", ""
		}
	} else {
		expiresAt, _ := strconv.ParseInt(result["expiresAt"], 10, 64)
		pass, _ := ValidateToken(expiresAt, true)
		if pass {
			return http.StatusOK, "用户已登录", result["token"]
		} else {
			return http.StatusFound, "token不可用或已过期", ""
		}
	}
}

func loginHandler(c *gin.Context) {

	//获取客户端指纹
	clientMark := strings.Replace(c.GetHeader("Authorization"), "Bearer ", "", 1)
	if clientMark == "" {
		c.JSON(http.StatusForbidden, gin.H{"status": "Client未激活"})
		return
	}

	var json models.Person
	if err := c.ShouldBindJSON(&json); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"status": err.Error()})
		return
	}

	person, err := db.GetPersonInfo(json.Name)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"status": "用户不存在"})
		return
	}

	if json.Password != person.Password {
		c.JSON(http.StatusUnauthorized, gin.H{"status": "密码错误"})
		return
	}

	//生成token
	var expireSecond = int64(3600)
	token, expiresAt, err := token.GenerateToken(person.Id, person.Name, expireSecond)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": "生成token失败"})
		return
	}

	//保存到cache
	cache_err := cache.SaveToken(clientMark, token, expiresAt)
	if cache_err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": "token保存到cache失败"})
		return
	}
	//保存到数据库
	record := models.Record{
		Token:      token,
		ClientMark: clientMark,
		ExpiresAt:  expiresAt,
		Valid:      true,
	}
	_, db_err := db.SaveRecord(record)
	if db_err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": "token保存到数据库失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": "you are logged in", "token": token})
}
